﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace FySystem.Logs
{
    /// <summary>
    /// 以文件方式存硬盘的日志
    /// </summary>
    public class FileLog : ILog
    {
        private FileStream _fs;
        private byte[] _lr = Encoding.UTF8.GetBytes("\n");

        /// <summary>
        /// 单个文件大小，默认为10M
        /// </summary>
        public long SingleFileSize { get; set; } = 10 * 1024 * 1024;
        /// <summary>
        /// 是否在控制台显示，默认不显示
        /// </summary>
        public bool ShowToConsole { get; set; } = false;
        /// <summary>
        /// 日志存放位置
        /// </summary>
        public string LogPath = string.Empty;
        /// <summary>
        /// 日志保留天数，默认为30天
        /// </summary>
        public int ExpiredDays { get; set; } = 30;

        public FileLog()
        {
            try
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    LogPath = AppDomain.CurrentDomain.BaseDirectory + "Logs\\";
                else
                    LogPath = AppDomain.CurrentDomain.BaseDirectory + "Logs/";

                if (Directory.Exists(LogPath) == false)
                    Directory.CreateDirectory(LogPath);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 创建文件流
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private void GetFileStream()
        {
            try
            {
                if (_fs == null)
                {
                    //如果为空
                    string fileName = $"{LogPath}Log.txt";
                    if (File.Exists(fileName))
                        _fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.Read);
                    else
                        _fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
                }
                else if (_fs.Length >= SingleFileSize)
                {
                    //如果不为空并且单文件大小已经达到了上限
                    if (ExpiredDays > 0)
                        DeleteExpiredFiles();

                    if (_fs != null)
                    {
                        _fs.Flush();
                        _fs.Dispose();
                    }

                    string fileName = $"{LogPath}Log.txt";
                    File.Move(fileName, $"{LogPath}Log_{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt");

                    _fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 删除过期文件
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void DeleteExpiredFiles()
        {
            try
            {
                Task task = new Task(() =>
                {
                    try
                    {
                        FileInfo[] files = new DirectoryInfo(LogPath).GetFiles();
                        if (files != null)
                        {
                            foreach (var file in files)
                            {
                                if ((DateTime.Now - file.CreationTime).TotalDays > ExpiredDays && file.Name != "Log.txt")
                                    file.Delete();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                });
                task.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void WriteLog(Span<LogItem> logs)
        {
            try
            {
                GetFileStream();

                foreach(var log in logs)
                {
                    string str = $"{DateTime.Now}#iserr:{(log.IsErr == true ? "1" : "0")}#{(log.Title == null ? "" : log.Title)}#{log.Log}";
                    if (ShowToConsole)
                        Console.WriteLine(str);

                    byte[] byteData = Encoding.UTF8.GetBytes(str);
                    _fs.Write(byteData);
                    _fs.Write(_lr);
                    _fs.Flush();

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
